/*
 * AViewGUI.java
 * 
 * Copyright 2008 David D. Emory
 * 
 * This file is part of Five Points. See <http://www.fpdev.org> for
 * additional information regarding the project.
 * 
 * Five Points is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * Five Points is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with Five Points.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.fpdev.apps.rtemaster.gui;

import org.fpdev.core.trip.Trip;
import org.fpdev.apps.rtemaster.gui.map.MapPanel;
import org.fpdev.util.gui.GUIFactory;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import org.fpdev.core.data.LegacyDB;
import org.fpdev.apps.rtemaster.GUIOutputAcceptor;
import org.fpdev.apps.rtemaster.RouteMaster;
import java.awt.event.*;
import java.util.HashMap;
import java.util.Map;
import javax.swing.*;
import javax.swing.border.BevelBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.fpdev.core.SysProps;
import org.fpdev.apps.rtemaster.RMEvent;
import org.fpdev.apps.rtemaster.EventTypes;
import org.fpdev.apps.rtemaster.gui.map.MapCanvas;
import org.fpdev.apps.rtemaster.gui.map.MapDrawItems;
import org.fpdev.util.gui.MessageArea;

public class RMGUI extends JFrame implements ActionListener, GUIOutputAcceptor {

  private RouteMaster rm_;
  private MapPanel mapPanel_;
  private OverviewMap overviewMap_;
  private ScenariosPanel scenPanel_;
  private MapMainToolbar mainBar_;
  private MapModeToolbar modeBar_;
  private LinkOptionsPanel linkOptionsPanel_;
  private TPathOptionsPanel tPathOptionsPanel_;
  private StationSelectionPanel staSelPanel_;
  private RouteSelectionPanel routeSelPanel_;
  private AnalysisPanel analysisOptionsPanel_;
  private JPanel mapOptionsPanel_;
  private JSplitPane mapSplitPane_, leftSplitPane_, rightSplitPane_;
  private JTabbedPane modePane_;
  private JPanel analysisModePanel_,  routeModePanel_,  mapModePanel_,  leftPanel_,  leftCenterPanel_,  centerPanel_,  centerPanelMap_,  mapContainer_,  rightPanel_,  statusBar_;
  private TimetablePanel rightPanelTable_;
  private JToggleButton mapTBtn_,  tableTBtn_;
  
  // details panel
  private LowerPanel lowerPanel_;
  //private int detailsPanelHeight_;

  
  // program output box in lower left corner
  private MessageArea msgArea_;
  
  // lower status bar elements
  private JLabel statusText_, baseNetLabel_;
  private JProgressBar progressBar_;
  
  // persitent frames, dialogs, etc.
  private LandmarksFrame landmarksFrame_;
  private StreetAliasFrame streetAliasFrame_;
  private ImportRouteShpFrame impRteShpFrame_;
  //private LinkNameDialog linkNameDialog_;
  
  private int globalClickAction_,  specialClickAction_;
  private Map<Mode, Integer> modeClickActions_;
  private int prevNodeMode_;
  //private int rightPanelWidth_;
  private Mode mode_;

  // enumeration for current viewer mode
  public enum Mode {

    ANALYSIS(0),
    ROUTE(1),
    STATION(2),
    MAP(3);

    private int index_;

    private Mode(int index) { index_ = index; }

    private int index() {
      return index_;
    }
  }
  
  
  public final static int SPECIAL_NONE = 0;
  public final static int SPECIAL_SELNODE = -10;
  public final static int SPECIAL_SELLINK = -20;
  // to clean up: 
  public final static int SPECIAL_SELNODE_LM = -11;
  public final static int SPECIAL_SELNODE_IMPTEXT_1ST = -12;
  public final static int SPECIAL_SELNODE_IMPTEXT_2ND = -13;
  public final static int SPECIAL_SELLINK_RENAME = -21;

  public RMGUI(RouteMaster rm) {
    super("Five Points RouteMaster");
    rm_ = rm;

    mode_ = Mode.ANALYSIS;

    globalClickAction_ = MapMainToolbar.ACT_ZOOMRANGE;
    modeClickActions_ = new HashMap<Mode, Integer>();

    prevNodeMode_ = 0;
    specialClickAction_ = 0;
    initComponents();
    //landmarksFrame_ = new LandmarksFrame(av);
    impRteShpFrame_ = new ImportRouteShpFrame(rm, this);
    streetAliasFrame_ = new StreetAliasFrame(rm);

    /*addComponentListener(new ComponentAdapter() {
      @Override
      public void componentResized(ComponentEvent e) {
        System.out.println("gui resized");
      }
    });*/

    mapPanel_.addComponentListener(new ComponentAdapter() {
      @Override
      public void componentResized(ComponentEvent e) {
        System.out.println("map resized");
        mapPanel_.resized();
      }
    });
    
    /*rightPanel_.addComponentListener(new ComponentAdapter() {
      @Override
      public void componentResized(ComponentEvent e) {
        System.out.println("rightPanel resized");
        System.out.println("new rp w="+rightPanel_.getWidth()+"("+rightSplitPane_.getDividerSize()+")");
        rightPanelWidth_ = rightPanel_.getWidth()+rightSplitPane_.getDividerSize();
      }
    });

    leftPanel_.addComponentListener(new ComponentAdapter() {
      @Override
      public void componentResized(ComponentEvent e) {
        System.out.println("leftPanel resized");        
      }
    });*/

    mapPanel_.resized();

    setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
  }

  private void initComponents() {

    addWindowListener(new WindowAdapter() {

      @Override
      public void windowClosing(WindowEvent evt) {
        rm_.shutDown();
      }
    });

    double x = Double.valueOf(rm_.getEngine().getDataPackage().getProperty(SysProps.INIT_X));
    double y = Double.valueOf(rm_.getEngine().getDataPackage().getProperty(SysProps.INIT_Y));
    double res = Double.valueOf(rm_.getEngine().getDataPackage().getProperty(SysProps.INIT_RES));
    
    mapPanel_ = new MapPanel(rm_, this, x, y, res);

    modePane_ = new JTabbedPane();

    //ButtonGroup btnGroup = new ButtonGroup();

    mainBar_ = new MapMainToolbar(rm_);
    modeBar_ = new MapModeToolbar(rm_, mapPanel_);

    JPanel toolbars = new JPanel(new GridLayout(2, 1));
    //toolbars.setLayout(new BoxLayout(toolbars, BoxLayout.Y_AXIS));
    toolbars.add(mainBar_);
    toolbars.add(modeBar_);

    mapContainer_ = new JPanel(new GridLayout(1, 1));
    mapContainer_.add(mapPanel_);
    //mapContainer.add(modeBar_, BorderLayout.NORTH);

    // DETAILS PANEL
    lowerPanel_ = new LowerPanel(rm_);
    //detailsPanelHeight_ = 235;

    centerPanelMap_ = new JPanel(new BorderLayout());
    centerPanelMap_.add(mapContainer_, BorderLayout.CENTER);
    centerPanelMap_.add(toolbars, BorderLayout.NORTH);

    rightPanelTable_ = new TimetablePanel(rm_);


    centerPanel_ = new JPanel(new GridLayout(1, 1));
    centerPanel_.add(centerPanelMap_);

    // LEFT PANEL COMPONENTS

    // toggle buttons
    mapTBtn_ = GUIFactory.newToggleButton("Map", 80, this);
    tableTBtn_ = GUIFactory.newToggleButton("Table", 80, this);
    ButtonGroup tBtnGrp = new ButtonGroup();
    tBtnGrp.add(mapTBtn_);
    tBtnGrp.add(tableTBtn_);
    mapTBtn_.setSelected(true);
    JPanel tBtnPanel = new JPanel();
    tBtnPanel.setLayout(new BoxLayout(tBtnPanel, BoxLayout.X_AXIS));
    tBtnPanel.add(Box.createHorizontalGlue());
    tBtnPanel.add(mapTBtn_);
    tBtnPanel.add(tableTBtn_);
    tBtnPanel.add(Box.createHorizontalGlue());
    tBtnPanel.setAlignmentX(JPanel.LEFT_ALIGNMENT);
    // ** options panel ** //

    //mapOptionsPanel_ = new JPanel();
    //mapOptionsPanel_.setLayout(new BoxLayout(mapOptionsPanel_, BoxLayout.Y_AXIS));
    //mapOptionsPanel_.setBorder(new EmptyBorder(2,2,2,2));

    analysisModePanel_ = new JPanel(new BorderLayout());
    analysisOptionsPanel_ = new AnalysisPanel(rm_);
    analysisModePanel_.add(analysisOptionsPanel_, BorderLayout.NORTH);

    routeSelPanel_ = new RouteSelectionPanel(rm_);
    routeSelPanel_.setAlignmentX(JPanel.LEFT_ALIGNMENT);
    tPathOptionsPanel_ = new TPathOptionsPanel(mapPanel_);
    tPathOptionsPanel_.setAlignmentX(JPanel.LEFT_ALIGNMENT);
    routeModePanel_ = new JPanel();
    routeModePanel_.setLayout(new BoxLayout(routeModePanel_, BoxLayout.Y_AXIS));
    routeModePanel_.add(routeSelPanel_);
    routeModePanel_.add(Box.createVerticalStrut(2));
    routeModePanel_.add(tBtnPanel);
    routeModePanel_.add(Box.createVerticalStrut(2));
    routeModePanel_.add(tPathOptionsPanel_);

    staSelPanel_ = new StationSelectionPanel(rm_);

    mapModePanel_ = new JPanel(new BorderLayout());
    linkOptionsPanel_ = new LinkOptionsPanel();
    mapModePanel_.add(linkOptionsPanel_, BorderLayout.NORTH);

    modePane_.add("Analysis", analysisModePanel_);
    modePane_.add("Routes", routeModePanel_);
    modePane_.add("Stations", staSelPanel_);
    modePane_.add("Map", mapModePanel_);

    modePane_.addChangeListener(new ChangeListener() {

      @Override
      public void stateChanged(ChangeEvent e) {
        switch (modePane_.getSelectedIndex()) {
          case 0:
            onNewMode(Mode.ANALYSIS);
            break;
          case 1:
            onNewMode(Mode.ROUTE);
            break;
          case 2:
            onNewMode(Mode.STATION);
            break;
          case 3:
            onNewMode(Mode.MAP);
            break;
        }
      }
    });
    modePane_.setFont(GUIFactory.MAIN_FONT);
    modePane_.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);

    // ** message box ** //
    msgArea_ = new MessageArea(10, 20);


    // ** left panel init ** //

    leftPanel_ = new JPanel(new BorderLayout());
    leftPanel_.add(modePane_, BorderLayout.CENTER);
    leftPanel_.add(msgArea_, BorderLayout.SOUTH);


    // RIGHT PANEL 

    double wx1 = rm_.getEngine().getBaseNet().getMinNodeXCoord(); //av_.getEngine().getDB().getMinMax("min", "x", "nodes");
    double wy1 = rm_.getEngine().getBaseNet().getMinNodeYCoord(); //av_.getEngine().getDB().getMinMax("min", "y", "nodes");
    double wx2 = rm_.getEngine().getBaseNet().getMaxNodeXCoord(); //av_.getEngine().getDB().getMinMax("max", "x", "nodes");
    double wy2 = rm_.getEngine().getBaseNet().getMaxNodeYCoord(); //av_.getEngine().getDB().getMinMax("max", "y", "nodes");
    //overviewMap_ = new OverviewMap(av_, 120, 120, wx1, wy1, wx2, wy2);

    scenPanel_ = new ScenariosPanel(rm_.getEngine().getScenarios(), rm_, this);

    rightPanel_ = new JPanel(new BorderLayout());
    //rightPanel_.add(overviewMap_, BorderLayout.NORTH);
    rightPanel_.add(scenPanel_, BorderLayout.CENTER);
    System.out.println("added scenPanel");

    // SPLIT PANES

    rightSplitPane_ = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
            centerPanel_, rightPanel_);
    
    rightSplitPane_.setResizeWeight(1);
    rightSplitPane_.setDividerLocation(520);


    leftSplitPane_ = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
            leftPanel_, rightSplitPane_);
    leftSplitPane_.setDividerLocation(256);
    //splitPane_.setContinuousLayout(false);

    // STATUS BAR
    statusText_ = new JLabel("hello");
    JPanel statusBarRight = GUIFactory.newRowPanel();
    baseNetLabel_ = GUIFactory.newLabel("basenet");
    baseNetLabel_.setBorder(new BevelBorder(BevelBorder.LOWERED));

    progressBar_ = new JProgressBar();
    statusBarRight.add(progressBar_);
    statusBarRight.add(Box.createHorizontalStrut(4));
    statusBarRight.add(baseNetLabel_);
    statusBar_ = new JPanel(new BorderLayout());
    statusBar_.add(Box.createRigidArea(new Dimension(2, 18)), BorderLayout.WEST);
    statusBar_.add(statusText_, BorderLayout.CENTER);
    statusBar_.add(statusBarRight, BorderLayout.EAST);

    JPanel mainPanel = new JPanel(new BorderLayout());
    mainPanel.add(leftSplitPane_, BorderLayout.CENTER);
    mainPanel.add(statusBar_, BorderLayout.SOUTH);

    getContentPane().add(mainPanel);
    initMenus();
    initMenuBar();
    updateUndoRedo();
    setJMenuBar(menuBar_);

    pack();
    setSize(new Dimension(1000, 750));
    setLocationRelativeTo(null);
    setVisible(true);
  }
  
  /////////////////////////// MENUS /////////////////////////////
  private JMenuBar menuBar_;
  private JMenu fileMenu_,  editMenu_,  viewMenu_,  routeMenu_,  mapMenu_,  buildMenu_,  toolsMenu_,  dbMenu_,  helpMenu_;
  private JMenuItem miFileArchiveDP_,  miFileRestoreDP_,  miFileSaveStations_,  miFileSaveRoutes_,  miFileImpLinkData_;
  private JMenuItem miEditUndo_,  miEditRedo_; // these stay
  private JMenuItem miViewClearTrip_,  miViewClearLinkSel_,  miViewZoomToLinkSel_,  miViewToggleStreetNet_,  miViewToggleListPanel_,  miViewToggleRouteNet_;
  private JMenuItem miViewNodeDispHide_,  miViewNodeDispStandard_,  miViewNodeDispID_,  miViewNodeDispEditOnly_;
  private JMenuItem miViewLinkDispErrName_,  miViewLinkDispErrAddr_;
  private JMenuItem miMapSetAddr_,  miMapFixAddr_;
  private JMenuItem miRouteImportText_,  miRouteGenXML_;
  private JMenuItem miBuildInitTEs_,  miBuildClearTEs_;
  private JMenu debugMenu_;
  
  //private Map<Integer, JMenu> modeMenus_;
  private void initMenus() {
    menuBar_ = new JMenuBar();

    // file menu
    fileMenu_ = new JMenu("File");
    newEventMenuItem(EventTypes.FILEMENU_SWITCH_DATA_PACKAGE, "Switch Data Package", fileMenu_);
    //miFileArchiveDP_ = newMenuItem("Archive Package to Disk", fileMenu_);
    //miFileRestoreDP_ = newMenuItem("Restore Package from Archive", fileMenu_);
    fileMenu_.add(new JSeparator());
    miFileSaveStations_ = newMenuItem("Save Stations", fileMenu_);
    miFileSaveRoutes_ = newMenuItem("Save Routes", fileMenu_);
    newEventMenuItem(EventTypes.FILEMENU_WRITE_NETWORK_SHP, "Write Network SHP", fileMenu_);
    newEventMenuItem(EventTypes.FILEMENU_WRITE_NETWORK_POSTGIS, "Write Network Postgis", fileMenu_);
    /*newEventMenuItem(EventTypes.FILEMENU_WRITE_NETWORK_CACHE, "Write Network to Cache", fileMenu_);
    newEventMenuItem(EventTypes.FILEMENU_READ_NETWORK_CACHE, "Read Network from Cache", fileMenu_);
    newEventMenuItem(EventTypes.FILEMENU_WRITE_TRANSIT_CACHE, "Write Transit Data to Cache", fileMenu_);
    newEventMenuItem(EventTypes.FILEMENU_READ_TRANSIT_CACHE, "Read Transit Data from Cache", fileMenu_);*/
    fileMenu_.add(new JSeparator());
    newEventMenuItem(EventTypes.FILEMENU_EXPORT_LINKS_SHAPEFILE, "Export Links Shapefile", fileMenu_);
    newEventMenuItem(EventTypes.FILEMENU_EXPORT_ROUTES_SHAPEFILE, "Export Routes Shapefile", fileMenu_);
    newEventMenuItem(EventTypes.FILEMENU_EXPORT_STATIONS_SHAPEFILE, "Export Stations Shapefile", fileMenu_);
    fileMenu_.add(new JSeparator());
    newEventMenuItem(EventTypes.FILEMENU_EXIT, "Exit", fileMenu_);

    // EDIT MENU
    editMenu_ = new JMenu("Edit");

    // keep references to undo/redo menu items to change displayed text 
    miEditUndo_ = newEventMenuItem(EventTypes.EDITMENU_UNDO, "Undo", editMenu_, KeyStroke.getKeyStroke(KeyEvent.VK_Z, KeyEvent.CTRL_DOWN_MASK));
    miEditRedo_ = newEventMenuItem(EventTypes.EDITMENU_REDO, "Redo", editMenu_, KeyStroke.getKeyStroke(KeyEvent.VK_Y, KeyEvent.CTRL_DOWN_MASK));

    newEventMenuItem(EventTypes.EDITMENU_CANCEL_CURRENT_OPERATION, "Cancel Current Action", editMenu_);

    // view menu
    viewMenu_ = new JMenu("View");
    miViewClearTrip_ = newMenuItem("Clear Annotations", viewMenu_);
    miViewZoomToLinkSel_ = newMenuItem("Zoom to Selected Links", viewMenu_);
    miViewToggleStreetNet_ = newCheckBoxMenuItem("Show Street Network", true, viewMenu_);
    miViewToggleListPanel_ = newCheckBoxMenuItem("Show Trip Panel", false, viewMenu_);
    JMenu mapNodeDispSubmenu = new JMenu("Node Display Options");
    ButtonGroup nodeDispGroup = new ButtonGroup();
    miViewNodeDispHide_ = newRadioButtonMenuItem("Do Not Show Nodes", false, mapNodeDispSubmenu, nodeDispGroup);
    miViewNodeDispStandard_ = newRadioButtonMenuItem("Show Nodes", false, mapNodeDispSubmenu, nodeDispGroup);
    miViewNodeDispID_ = newRadioButtonMenuItem("Show Nodes with IDs", false, mapNodeDispSubmenu, nodeDispGroup);
    miViewNodeDispEditOnly_ = newRadioButtonMenuItem("Show Nodes in Edit Mode Only", true, mapNodeDispSubmenu, nodeDispGroup);
    viewMenu_.add(mapNodeDispSubmenu);

    JMenu mapLinkDispSubmenu = new JMenu("Link Display Options");
    ButtonGroup linkDispGroup = new ButtonGroup();
    miViewLinkDispErrName_ = newRadioButtonMenuItem("Name", true, mapLinkDispSubmenu, linkDispGroup);
    miViewLinkDispErrAddr_ = newRadioButtonMenuItem("Address", false, mapLinkDispSubmenu, linkDispGroup);
    viewMenu_.add(mapLinkDispSubmenu);

    miViewToggleRouteNet_ = newCheckBoxMenuItem("Show Route Network", false, viewMenu_);
    newEventMenuItem(EventTypes.VIEWMENU_MANAGE_LANDMARKS, "Show Landmarks Manager", viewMenu_);
    newEventMenuItem(EventTypes.VIEWMENU_MANAGE_STREETALIASES, "Show Street Name Aliases Manager", viewMenu_);
    
    
    // route menu
    routeMenu_ = new JMenu("Route");
    newEventMenuItem(EventTypes.RTEMENU_IMPORT_NAMES_TEXT, "Import Route Names from Text", routeMenu_);
    //miRouteLoadDBF_ = newMenuItem("Load Timetables from File", routeMenu_);
    newEventMenuItem(EventTypes.RTEMENU_AUTOLOAD_TIMETABLES, "Auto-Load Timetables", routeMenu_, KeyStroke.getKeyStroke(KeyEvent.VK_A, KeyEvent.CTRL_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK));
    newEventMenuItem(EventTypes.RTEMENU_CLEAR_TIMETABLES, "Clear Timetables", routeMenu_, KeyStroke.getKeyStroke(KeyEvent.VK_C, KeyEvent.CTRL_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK));
    newEventMenuItem(EventTypes.RTEMENU_IMPORT_PATH_INTERNAL, "Copy Path from Existing", routeMenu_);
    miRouteImportText_ = newMenuItem("Import Path from Text", routeMenu_);
    miRouteGenXML_ = newMenuItem("Generate XML for Web", routeMenu_);
    newEventMenuItem(EventTypes.RTEMENU_IMPORT_SHP, "Import Routes from Shapefile", routeMenu_);
    newEventMenuItem(EventTypes.RTEMENU_SHOW_IMPORT_SHP_FRAME, "Show Import from Shapefile Frame", routeMenu_);
    newEventMenuItem(EventTypes.RTEMENU_IMPORT_GTFS, "Import Routes from GTFS", routeMenu_);
    newEventMenuItem(EventTypes.RTEMENU_EXPORT_GTFS, "Export to GTFS", routeMenu_);

    // map menu
    mapMenu_ = new JMenu("Map");
    newEventMenuItem(EventTypes.MAPMENU_CLEAR_SELECTED, "Clear Selected Nodes/Links", mapMenu_);
    newEventMenuItem(EventTypes.MAPMENU_DELETE_SELECTED, "Delete Selected Nodes/Links", mapMenu_);
    newEventMenuItem(EventTypes.MAPMENU_EDIT_LINK_PROPERTIES, "Edit Link Properties", mapMenu_);
    miMapSetAddr_ = newMenuItem("Specify Address Ranges", mapMenu_);
    miMapFixAddr_ = newMenuItem("Auto-Fix Address Ranges", mapMenu_);
    newEventMenuItem(EventTypes.MAPMENU_SIMPLIFY_SHPPTS, "Simplify Curvature", mapMenu_);
    newEventMenuItem(EventTypes.MAPMENU_OFFSET_LINKS, "Create Offset Links", mapMenu_);
    newEventMenuItem(EventTypes.MAPMENU_REVERSE_SHPPTS, "Reverse Shapepoints", mapMenu_);
    mapMenu_.addSeparator();
    newEventMenuItem(EventTypes.MAPMENU_IMPORT_LINKS, "Import Links from Shapefile", mapMenu_);
    newEventMenuItem(EventTypes.MAPMENU_IMPORT_STREETS_WIZARD, "Import Streets Wizard", mapMenu_);
    newEventMenuItem(EventTypes.MAPMENU_IMPORT_ELEV_DATA, "Import Elevation Data", mapMenu_);
    newEventMenuItem(EventTypes.MAPMENU_IMPORT_ZIP_DATA, "Import ZIP Code Data", mapMenu_);
    
    // BUILD MENU
    buildMenu_ = new JMenu("Build");
    miBuildInitTEs_ = newMenuItem("Init Transit Elements", buildMenu_);
    miBuildClearTEs_ = newMenuItem("Clear Transit Elements", buildMenu_);
    //miBuildInitAST_ = newMenuItem("Init Address Search Tree", buildMenu_);

    
    // DB MENU

    dbMenu_ = new JMenu("DB");

    if(rm_.getEngine().getDB() != null)
      newEventMenuItem(EventTypes.DBMENU_MIGRATE, "Migrate DB to " + (rm_.getEngine().getDB().getRDBMS() == LegacyDB.DB_DERBY ? "MySQL" : "Derby"), dbMenu_);
    
    JMenu baseNetTablesSubmenu = new JMenu("Base Network Table Operations");
    newEventMenuItem(EventTypes.DBMENU_INIT_BASENET_TABLES, "Init All BaseNet Tables", baseNetTablesSubmenu);
    newEventMenuItem(EventTypes.DBMENU_CLEAR_BASENET_TABLES, "Clear All BaseNet Tables", baseNetTablesSubmenu);
    newEventMenuItem(EventTypes.DBMENU_INIT_NODES_TABLE, "Init Nodes Table", baseNetTablesSubmenu);
    newEventMenuItem(EventTypes.DBMENU_CLEAR_NODES_TABLE, "Clear Nodes Table", baseNetTablesSubmenu);
    newEventMenuItem(EventTypes.DBMENU_INIT_LINKS_TABLE, "Init Links Table", baseNetTablesSubmenu);
    newEventMenuItem(EventTypes.DBMENU_CLEAR_LINKS_TABLE, "Clear Links Table", baseNetTablesSubmenu);
    newEventMenuItem(EventTypes.DBMENU_INIT_ADDR_TABLE, "Init Address Ranges Table", baseNetTablesSubmenu);
    newEventMenuItem(EventTypes.DBMENU_INIT_ISECT_TABLE, "Init Isect Keys Table", baseNetTablesSubmenu);
    newEventMenuItem(EventTypes.DBMENU_CLEAR_ISECT_TABLE, "Clear Isect Keys Table", baseNetTablesSubmenu);
    newEventMenuItem(EventTypes.DBMENU_INIT_ELEV_TABLE, "Init Elevation Table", baseNetTablesSubmenu);
    newEventMenuItem(EventTypes.DBMENU_DROP_ELEV_TABLE, "Drop Elevation Table", baseNetTablesSubmenu);
    newEventMenuItem(EventTypes.DBMENU_INIT_SCENLINKTYPES_TABLE, "Init Scenario-Specific Link-Types Table", baseNetTablesSubmenu);
    newEventMenuItem(EventTypes.DBMENU_DROP_SCENLINKTYPES_TABLE, "Drop Scenario-Specific Link-Types Table", baseNetTablesSubmenu);
    dbMenu_.add(baseNetTablesSubmenu);

    newEventMenuItem(EventTypes.DBMENU_DELETE_SINGLE_LINK, "Delete Single Link", dbMenu_);
    newEventMenuItem(EventTypes.DBMENU_CLEAR_LANDMARKS_TABLE, "Clear Landmarks Table", dbMenu_);

    JMenu serverTablesSubmenu = new JMenu("Server Table Operations");
    newEventMenuItem(EventTypes.DBMENU_CREATE_LOG_TABLES, "Create Query Log Tables", serverTablesSubmenu);
    newEventMenuItem(EventTypes.DBMENU_DROP_LOG_TABLES, "Drop Query Log Tables", serverTablesSubmenu);
    serverTablesSubmenu.addSeparator();
    newEventMenuItem(EventTypes.DBMENU_CREATE_TRIPLINKS_TABLE, "Create Trip Links Tables", serverTablesSubmenu);
    newEventMenuItem(EventTypes.DBMENU_DROP_TRIPLINKS_TABLE, "Drop Trip Links Tables", serverTablesSubmenu);
    serverTablesSubmenu.addSeparator();
    newEventMenuItem(EventTypes.DBMENU_CREATE_PING_TABLE, "Create Ping Table", serverTablesSubmenu);
    newEventMenuItem(EventTypes.DBMENU_DROP_PING_TABLE, "Drop Ping Table", serverTablesSubmenu);
    dbMenu_.add(serverTablesSubmenu);
    
    // debug menu
    debugMenu_ = new JMenu("Debug");
    newEventMenuItem(EventTypes.DEBUGMENU_GARBAGE_COLLECT, "Garbage Collect", debugMenu_);
    newEventMenuItem(EventTypes.DEBUGMENU_ACTION, "Debug Action", debugMenu_);

    // ABOUT MENU

    helpMenu_ = new JMenu("Help");
    newEventMenuItem(EventTypes.HELPMENU_ABOUT, "About", helpMenu_);
  }

  public void initMenuBar() {
    menuBar_.removeAll();
    menuBar_.add(fileMenu_);
    menuBar_.add(editMenu_);

    menuBar_.add(routeMenu_);
    routeMenu_.setEnabled(mode_ == Mode.ROUTE);
    menuBar_.add(mapMenu_);
    mapMenu_.setEnabled(mode_ == Mode.MAP);

    menuBar_.add(buildMenu_);
    //menuBar_.add(toolsMenu_);
    menuBar_.add(dbMenu_);
    menuBar_.add(viewMenu_);
    menuBar_.add(debugMenu_);
    menuBar_.add(helpMenu_);
  }

  private JMenuItem newMenuItem(String text, JMenu menu) {
    JMenuItem item = new JMenuItem(text);
    item.addActionListener(this);
    menu.add(item);
    return item;
  }

  private JMenuItem newEventMenuItem(int eventType, String text, JMenu menu) {
    return newEventMenuItem(eventType, text, menu, null);
  }

  private JMenuItem newEventMenuItem(int eventType, String text, JMenu menu, KeyStroke accel) {
    JMenuItem item = new EventMenuItem(eventType, text);
    item.addActionListener(this);
    if (accel != null) {
      item.setAccelerator(accel);
    }
    menu.add(item);
    return item;
  }

  private JRadioButtonMenuItem newRadioButtonMenuItem(String text, boolean selected, JMenu menu, ButtonGroup btnGroup) {
    JRadioButtonMenuItem item = new JRadioButtonMenuItem(text, selected);
    item.addActionListener(this);
    menu.add(item);
    btnGroup.add(item);
    return item;
  }

  private JCheckBoxMenuItem newCheckBoxMenuItem(String text, boolean selected, JMenu menu) {
    JCheckBoxMenuItem item = new JCheckBoxMenuItem(text, selected);
    item.addActionListener(this);
    menu.add(item);
    return item;
  }

  public void updateUndoRedo() {
    boolean undoExists = rm_.getHistory().undoActionExists();
    String undoText = "Undo " + (undoExists ? rm_.getHistory().undoActionName() : "");
    miEditUndo_.setEnabled(undoExists);
    miEditUndo_.setText(undoText);
    mainBar_.getUndoButton().setEnabled(undoExists);
    mainBar_.getUndoButton().setToolTipText(undoText);

    boolean redoExists = rm_.getHistory().redoActionExists();
    String redoText = "Redo " + (redoExists ? rm_.getHistory().redoActionName() : "");
    miEditRedo_.setEnabled(redoExists);
    miEditRedo_.setText(redoText);
    mainBar_.getRedoButton().setEnabled(redoExists);
    mainBar_.getRedoButton().setToolTipText(redoText);
  }

  ///////////////////////////////////// 

  public void showMap() {
    Dimension d = centerPanel_.getSize();
    centerPanel_.removeAll();
    centerPanel_.add(centerPanelMap_);
    centerPanel_.repaint();
    centerPanel_.revalidate();
  }

  public void showTimetable() {
    Dimension d = centerPanel_.getSize();
    centerPanel_.removeAll();
    centerPanel_.add(rightPanelTable_);
    centerPanel_.setPreferredSize(d);
    centerPanel_.repaint();
    centerPanel_.revalidate();
  }

  @Override
  public void actionPerformed(ActionEvent e) {

    if (e.getSource() instanceof EventMenuItem) {
      rm_.fireEvent(new RMEvent(((EventMenuItem) e.getSource()).getEventType()));
      return;
    }

    // Map/Route toggle btns
    if (e.getSource() == mapTBtn_) {
      showMap();
    }
    if (e.getSource() == tableTBtn_) {
      showTimetable();
    }

    // Menu Actions

    // FILE
    if (e.getSource() == miFileArchiveDP_) {
      rm_.getDataPackageOps().archivePackageToDisk();
    }
    if (e.getSource() == miFileRestoreDP_) {
      rm_.getDataPackageOps().restorePackageFromArchive();
    }
    if (e.getSource() == miFileSaveStations_) {
      rm_.getStationOps().writeStationsFile();
    }
    if (e.getSource() == miFileSaveRoutes_) {
      rm_.getRouteOps().writeRoutesFile();
    }

    // MAP    
    if (e.getSource() == miViewClearTrip_) {
      mapPanel_.getDrawItems().removeAll();
      rm_.getAnalysisOps().setStartLocation(null);
      rm_.getAnalysisOps().setEndLocation(null);
      this.getAnalysisOptionsPanel().getTripPlannerPanel().clearStartEndText();
      mapPanel_.refresh(false, false, true);
    }

    if (e.getSource() == miViewClearLinkSel_) {
      mapPanel_.getSelectedLinks().clear();
      mapPanel_.refresh(false, false, true);
    }
    if (e.getSource() == miViewZoomToLinkSel_) {
      mapPanel_.zoomToSelectedLinks();
    }
    if (e.getSource() == miViewNodeDispHide_) {
      mapPanel_.getCanvas().setNodeDispMode(MapCanvas.NODEDISP_HIDE);
      mapPanel_.refresh(false, true, false);
    }
    if (e.getSource() == miViewNodeDispStandard_) {
      mapPanel_.getCanvas().setNodeDispMode(MapCanvas.NODEDISP_STANDARD);
      mapPanel_.refresh(false, true, false);
    }
    if (e.getSource() == miViewNodeDispID_) {
      mapPanel_.getCanvas().setNodeDispMode(MapCanvas.NODEDISP_ID);
      mapPanel_.refresh(false, true, false);
    }
    if (e.getSource() == miViewNodeDispEditOnly_) {
      mapPanel_.getCanvas().setNodeDispMode(MapCanvas.NODEDISP_EDITONLY);
      mapPanel_.refresh(false, true, false);
    }

    if (e.getSource() == miViewLinkDispErrName_) {
      mapPanel_.getCanvas().setLinkDispMode(MapCanvas.LINKDISP_ERRNAME);
      mapPanel_.refresh(false, true, false);
    }

    if (e.getSource() == miViewLinkDispErrAddr_) {
      mapPanel_.getCanvas().setLinkDispMode(MapCanvas.LINKDISP_ERRADDR);
      mapPanel_.refresh(false, true, false);
    }

    if (e.getSource() == miViewToggleStreetNet_) {
      mapPanel_.setDrawStreetNetwork(miViewToggleStreetNet_.isSelected());
      mapPanel_.refresh(false, true, true);
    }

    if (e.getSource() == miViewToggleListPanel_) {
      if (miViewToggleListPanel_.isSelected()) {
        showLowerPanel();
      } else {
        hideLowerPanel();
      }
    }

    if (e.getSource() == miViewToggleRouteNet_) {
      mapPanel_.setDrawRouteNetwork(miViewToggleRouteNet_.isSelected());
      mapPanel_.refresh(false, false, true);
    }

    /*if (e.getSource() == miMapRenameLinks_) {
      av_.getNetworkOps().renameSelectedLinks();
    }
    if(e.getSource()==miMapLinkWalk_) {
    av_.setSelectedLinkWalkability();
    mapPanel_.update(true,false);
    }*/
    if (e.getSource() == miMapSetAddr_) {
      rm_.getNetworkOps().setSelectedLinkAddr();
      mapPanel_.refresh(false, true, false);
    }
    if (e.getSource() == miMapFixAddr_) {
      rm_.getNetworkOps().fixSelectedLinkAddr();
      mapPanel_.refresh(false, true, false);
    }

    // ROUTE
    if (e.getSource() == miRouteImportText_) {
      rm_.getRouteOps().importRoutePathFromText();
    }
    if (e.getSource() == miRouteGenXML_) {
      rm_.getRouteOps().generateXMLForWeb();
    }


    // BUILD
    if (e.getSource() == miBuildInitTEs_) {
      rm_.getEngine().buildRouteNetwork();
      mapPanel_.refresh(false, true, false);
    }
    if (e.getSource() == miBuildClearTEs_) {
      rm_.clearTransitElements();
      mapPanel_.refresh(false, true, false);
    }

  
  }

  @Override
  public void msg(String text) {
    msgArea_.msg(text, true);
  }

  public String getStatusText() {
    return statusText_.getText();
  }

  @Override
  public void statusText(String text) {
    statusText_.setText(text);
    statusText_.paintImmediately(0, 0, statusText_.getWidth(), statusText_.getHeight());// repaint();
  }

  public void updateBaseNetLabel() {
    baseNetLabel_.setText("N:"+rm_.getEngine().getBaseNet().nodeCount()+" L:"+rm_.getEngine().getBaseNet().linkCount());
  }
  private int lastPBValue_;  
  
  @Override
  public void setProgress(int value) {
    //System.out.println("prog: "+value);
    if(value == lastPBValue_) return;
    progressBar_.setValue(value);
    lastPBValue_ = value;
    progressBar_.paintImmediately(0, 0, progressBar_.getWidth(), progressBar_.getHeight());// repaint();
  }

  public MapPanel getMapPanel() {
    return mapPanel_;
  }

  public OverviewMap getOverviewMap() {
    return overviewMap_;
  }

  public TimetablePanel getTablePanel() {
    return rightPanelTable_;
  }

  public LinkOptionsPanel getLinkOptionsPanel() {
    return linkOptionsPanel_;
  }

  public StationSelectionPanel getStationSelectionPanel() {
    return staSelPanel_;
  }

  public RouteSelectionPanel getRouteSelectionPanel() {
    return routeSelPanel_;
  }

  public TPathOptionsPanel getTPathOptionsPanel() {
    return tPathOptionsPanel_;
  }

  public AnalysisPanel getAnalysisOptionsPanel() {
    return analysisOptionsPanel_;
  }

  public ScenariosPanel getScenariosPanel() {
    return scenPanel_;
  }

  //private Scenario oldScenario_;

  public void setMode(Mode mode) {
    modePane_.setSelectedIndex(mode.index());
    //modePane_.validate();
  }

  public Mode getMode() {
    return mode_;
  }

  public void onNewMode(Mode mode) {
    Mode oldmode = mode_;
    mode_ = mode;
    //if(mapClickAction_ >= 100) mapClickAction_ = 0;

    if (mode_ != Mode.ROUTE && tableTBtn_.isSelected()) {
      showMap();
      mapTBtn_.setSelected(true);
    }

    //if (oldmode == Mode.ROUTE) {
    //  oldScenario_ = getActiveScenario();
    //}
    if (mode_ == Mode.ROUTE) { // && oldScenario_ != getActiveScenario()) {
      routeSelPanel_.updateRoutes();
    }

    initMenuBar();
    menuBar_.revalidate();

    modeBar_.newMode(oldmode, mode_);
    mapPanel_.newMode(oldmode, mode_);
  }

  public void activeScenarioChanged() {
    if (mode_ == Mode.ROUTE) {
      routeSelPanel_.updateRoutes();
    }
    mapPanel_.refresh(true, true, true);
  }

  // used for map-related prompts from dialogs, etc.
  public void setSpecialClickAction(int sca) {
    specialClickAction_ = sca;
  }

  public void clearSpecialClickAction() {
    specialClickAction_ = RMGUI.SPECIAL_NONE;
    rm_.clearSpecialNodeClickHandler();
    rm_.clearSpecialLinkClickHandler();
  }

  public int getCurrentClickAction() {
    if (specialClickAction_ != 0) {
      return specialClickAction_;
    }
    return getSelectedToolbarAction();
  }

  public int getSelectedToolbarAction() {
    if (globalClickAction_ > 0) {
      return globalClickAction_;
    }
    if (!modeClickActions_.containsKey(mode_)) {
      return 0;
    }
    return modeClickActions_.get(mode_);
  }

  public void setToolbarAction(int action) {
    //mapClickAction_ = action;
    if (action < 100) {
      globalClickAction_ = action;
      modeBar_.clearSelected();
    } else {
      modeClickActions_.put(mode_, action);
      globalClickAction_ = 0;
      mainBar_.clearSelected();
    }

    if (action == MapModeToolbar.ACT_MNEWSHPPT || action == MapModeToolbar.ACT_MDELSHPPT || action == MapModeToolbar.ACT_MDRAGSHPPT) {

      if (mapPanel_.getCanvas().getNodeDispMode() != MapCanvas.NODEDISP_SHPPT) {
        prevNodeMode_ = mapPanel_.getCanvas().getNodeDispMode();
        mapPanel_.getCanvas().setNodeDispMode(MapCanvas.NODEDISP_SHPPT);
        mapPanel_.refresh(false, true, true);
      }
    } else if (prevNodeMode_ > 0) {
      mapPanel_.getCanvas().setNodeDispMode(prevNodeMode_);
      mapPanel_.refresh(false, true, true);
    }

    newToolbarAction(true);
  }

  public void newToolbarAction(boolean reval) {
    setSpecialClickAction(SPECIAL_NONE);
    mapPanel_.newClickAction();
    if (mapOptionsPanel_ == null || mode_ != Mode.MAP) {
      return;
    }

    // make any changes to the map options panel, if needed:
    if (reval) {
      mapOptionsPanel_.removeAll();
    }
    switch (getSelectedToolbarAction()) {
      case MapModeToolbar.ACT_MNEWLINK:
        mapOptionsPanel_.add(linkOptionsPanel_);
        break;
    }
    if (reval) {
      mapOptionsPanel_.revalidate();
    }
  }

  public LandmarksFrame getLandmarksFrame() {
    return landmarksFrame_;
  }
  
  public StreetAliasFrame getStreetAliasFrame() {
    return streetAliasFrame_;
  }

  public ImportRouteShpFrame getImportRouteShpFrame() {
    return impRteShpFrame_;
  }

  /*public LinkNameDialog getLinkNameDialog() {
    return linkNameDialog_;
  }

  public void setLinkNameDialog(LinkNameDialog lnd) {
    linkNameDialog_ = lnd;
  }*/

  public void zoomToTrip(Trip trip) {
    if (trip == null) {
      lowerPanel_.clearTable();
      hideLowerPanel();
      return;
    }
    rm_.getGUI().getMapPanel().zoomDrawable(MapDrawItems.BEST_TRIP, 0.1);
  }


  // LOWER PANEL

  public LowerPanel getLowerPanel() {
    return lowerPanel_;
  }

  public void showLowerPanel() {
    showLowerPanel(lowerPanel_.getLastHeight());
  }

  public void showLowerPanel(int height) {
    //if(mapSplitPane_.getMaximumDividerLocation() - mapSplitPane_.getDividerLocation() < 10)
    mapSplitPane_ = new JSplitPane(JSplitPane.VERTICAL_SPLIT, mapPanel_, lowerPanel_);
    mapContainer_.removeAll();
    mapContainer_.add(mapSplitPane_);
    mapSplitPane_.setDividerLocation(mapContainer_.getHeight() - height - mapSplitPane_.getDividerSize() - 1);
    mapContainer_.revalidate();
    miViewToggleListPanel_.setSelected(true);
  }

  public void hideLowerPanel() {
    //mapSplitPane_.setDividerLocation(1.0);
    if (mapSplitPane_ == null || mapSplitPane_.getComponentCount() == 0) {
      return;
    }
    lowerPanel_.captureLastHeight();
    //detailsPanelHeight_ = lowerPanel_.getHeight();
    if (mode_ == Mode.ANALYSIS) {
      mapPanel_.getDrawItems().removeItem(MapDrawItems.AN_TRANSIT_PATH);
    }
    mapSplitPane_.removeAll();
    mapContainer_.removeAll();
    mapContainer_.add(mapPanel_);
    mapContainer_.revalidate();
    miViewToggleListPanel_.setSelected(false);
  }

  public class EventMenuItem extends JMenuItem {

    private int eventType_;

    public EventMenuItem(int type, String text) {
      super(text);
      eventType_ = type;
    }

    public int getEventType() {
      return eventType_;
    }
  }
}




























